package com.sprouting.ops.controller;

import cn.dev33.satoken.exception.NotRoleException;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.sprouting.ops.annotations.invoke.IdempotentSingle;
import com.sprouting.ops.interfaces.AddGroup;
import com.sprouting.ops.interfaces.ConstantBase;
import com.sprouting.ops.interfaces.ConstantPower;
import com.sprouting.ops.interfaces.UpdGroup;
import com.sprouting.ops.model.OpsRole;
import com.sprouting.ops.model.OpsRoleAuthority;
import com.sprouting.ops.model.ResultJson;
import com.sprouting.ops.model.bo.OpsRoleSaveUpdBo;
import com.sprouting.ops.model.qo.RoleQo;
import com.sprouting.ops.service.OpsRoleService;
import com.sprouting.ops.utils.CheckTool;
import com.sprouting.ops.utils.EntityTool;
import com.sprouting.ops.utils.IdTool;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.ArrayList;
import java.util.List;

/**
 * 角色
 *
 * @author ：LX（长沙麓谷）
 * @date 创建时间： 2023/3/18 20:22
 */
@Slf4j
@RestController
@RequestMapping("role")
public class OpsRoleController {

    @Autowired
    private OpsRoleService opsRoleService;

    /**
     * 获取：当前账号所拥有的角色集合
     * @return 角色集合
     */
    @GetMapping("getRoleList")
    public ResultJson getRoleList(){
        return ResultJson.success(StpUtil.getRoleList());
    }

    /**
     * 判断：当前账号是否拥有指定角色, 返回 true 或 false
     * @param role 角色
     * @return true 有角色 false 无角色
     */
    @PostMapping("hasRole")
    public ResultJson hasRole(String role){
        if (CheckTool.checkNull(role)){
            return ResultJson.errorCheck();
        }

        // 校验：当前账号是否含有指定角色标识, 如果验证未通过，则抛出异常: NotRoleException
        // StpUtil.checkRole("super-admin");

        return ResultJson.success(StpUtil.hasRole(role));
    }

    /**
     * 校验：当前账号是否含有指定角色标识 [指定多个，必须全部验证通过]
     * @param roleArray 角色列表
     * @return true 有角色 false 无角色
     */
    @PostMapping("checkRoleAnd")
    public ResultJson checkRoleAnd(String[] roleArray){
        if (CheckTool.checkNull(roleArray)){
            return ResultJson.errorCheck();
        }

        try {
            StpUtil.checkRoleAnd(roleArray);
        } catch (NotRoleException e) {
            return ResultJson.success(false);
        }
        return ResultJson.success(true);
    }

    /**
     * 校验：当前账号是否含有指定角色标识 [指定多个，只要其一验证通过即可]
     * @param roleArray 角色列表
     * @return true 有角色 false 无角色
     */
    @PostMapping("checkRoleOr")
    public ResultJson checkRoleOr(String[] roleArray){
        if (CheckTool.checkNull(roleArray)){
            return ResultJson.errorCheck();
        }

        try {
            StpUtil.checkRoleOr(roleArray);
        } catch (Exception e) {
            return ResultJson.success(false);
        }
        return ResultJson.success(true);
    }

    /**
     * 分页查询自己创建的角色和拥有的角色
     * @return
     */
    @PostMapping("/getPage")
    public ResultJson getPage(RoleQo query){
        if (query == null){
            query = new RoleQo();
        }
        Page page = new Page<>(query.getCurrent(), query.getSize());
        return ResultJson.success(opsRoleService.getPage(page, query));
    }

    /**
     * 分页获取用户拥有的角色
     * @param query 分页参数
     * @return
     */
    @PostMapping("/getRoleHave")
    public ResultJson<Page<OpsRole>> getRoleHave(RoleQo query){
        if (query == null){
            query = new RoleQo();
        }

        Page page = new Page<>(query.getCurrent(), query.getSize());
        if (StpUtil.hasRole(ConstantPower.Base.BASE_ROLE_CODE)){
            // 超管，查询全部
            log.info("[角色查询] 超级管理员查询全部角色");
        } else {
            query.setUserId(StpUtil.getLoginIdAsString());
        }

        return ResultJson.success(opsRoleService.getRoleHaveByUserIdPage(page, query));
    }

    /**
     * 保存角色
     * @param bo 角色
     * @return
     */
    @IdempotentSingle
    @PostMapping("/saveRole")
    public ResultJson saveRole(@Validated(AddGroup.class) OpsRoleSaveUpdBo bo){
        String msg = checkRole(bo, bo.getResourceIdList());
        if (msg != null){
            return ResultJson.error(msg);
        }

        OpsRole role = BeanUtil.copyProperties(bo, OpsRole.class);
        role.setId(IdTool.getId());
        role.setBaseData(ConstantBase.BaseData.NO);
        EntityTool.saveBase(role);

        List<OpsRoleAuthority> rolePowerList = buildRolePower(bo.getResourceIdList(), role.getId());
        opsRoleService.saveRole(role, rolePowerList);
        return ResultJson.success();
    }

    /**
     * 更新角色
     * @param bo 角色
     * @return
     */
    @IdempotentSingle
    @PostMapping("/updRole")
    public ResultJson updRole(@Validated(UpdGroup.class) OpsRoleSaveUpdBo bo){
        String msg = checkRole(bo, bo.getResourceIdList());
        if (msg != null){
            return ResultJson.error(msg);
        }

        OpsRole role = BeanUtil.copyProperties(bo, OpsRole.class);
        EntityTool.updBase(role);
        role.setBaseData(null);
        List<OpsRoleAuthority> rolePowerList = buildRolePower(bo.getResourceIdList(), role.getId());
        opsRoleService.updRole(role, rolePowerList);
        return ResultJson.success();
    }

    /**
     * 删除角色
     * 权限是重要数据，不给予批量删除
     * @param id 角色ID
     * @return
     */
    @PostMapping("/delRole")
    @IdempotentSingle
    public ResultJson delRole(String id){
        if (CheckTool.checkNull(id)){
            return ResultJson.errorCheck();
        }

        OpsRole role = opsRoleService.getById(id);
        if (role == null){
            return ResultJson.error("角色不存在");
        }
        if (isBaseRole(role)){
            return ResultJson.error("基础数据不允许操作");
        }

        opsRoleService.delRole(role);
        return ResultJson.success();
    }

    /**
     * 校验角色相关信息
     * @param role 角色
     * @param resourceIdList 权限ID
     * @return 非null则异常
     */
    private String checkRole(OpsRoleSaveUpdBo role, List<String> resourceIdList){
        if (CollUtil.isEmpty(resourceIdList)){
            return "请选择角色对应的权限";
        }
        OpsRole sqlRole = opsRoleService.getRoleByCode(role.getCode(), role.getId());
        if (sqlRole != null){
            return "当前角色代码已使用";
        }
        if (StrUtil.isNotEmpty(role.getId())){
            OpsRole roleDb = opsRoleService.getById(role.getId());
            if (isBaseRole(roleDb)){
                return "基础数据不允许操作";
            }
        }

        return null;
    }

    /**
     * 判断是否基础数据
     * @param role 待判断的角色
     * @return true 基础角色 false 非基础
     */
    private Boolean isBaseRole(OpsRole role){
        if (ConstantPower.Base.BASE_ROLE_CODE.equals(role.getCode())){
            return true;
        }
        if (!ConstantBase.BaseData.NO.equals(role.getBaseData())){
            return true;
        }

        return false;
    }

    /**
     * 构建角色、权限关系
     * @param resourceIdList 权限id
     * @param roleId 角色
     * @return
     */
    private List<OpsRoleAuthority> buildRolePower(List<String> resourceIdList, String roleId){
        //权限和角色关系
        List<OpsRoleAuthority> rolePowerList = new ArrayList<>();
        for (String id : resourceIdList){
            OpsRoleAuthority rolePower = new OpsRoleAuthority();
            rolePower.setId(IdTool.getId());
            rolePower.setRoleId(roleId);
            rolePower.setAuthorityId(id);

            rolePowerList.add(rolePower);
        }

        return rolePowerList;
    }
}
